﻿
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Caching.Distributed;


namespace Admin.NET.Core.Fitter
{
    //用法[OccurSimultaneously(3, "BillNo")]

    public class OccurSimultaneouslyActionFilter : IAsyncActionFilter
    {
        public string[] FactorNames { get; set; }
        public TimeSpan? AbsoluteExpirationRelativeToNow { get; set; }

        private readonly IDistributedCache _cache;
        private readonly ILogger<OccurSimultaneouslyActionFilter> _logger;

        public OccurSimultaneouslyActionFilter(IDistributedCache cache, ILogger<OccurSimultaneouslyActionFilter> logger)
        {
            _cache = cache;
            _logger = logger;
        }

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //整合为 
            var factorValues = new string[FactorNames.Length];
            //判断入参类型是  FromBody 还是 parameter1
            var isFromBody =
                context.ActionDescriptor.Parameters.Any(r => r.BindingInfo?.BindingSource == BindingSource.Body);
            //查找对应属性的值
            if (isFromBody)
            {
                var parameterValue = context.ActionArguments.FirstOrDefault().Value;
             
                factorValues = FactorNames.Select(name =>
                    parameterValue?.GetType().GetProperty(name)?.GetValue(parameterValue)?.ToString()).ToArray();
            }
            else
            {
                for (var index = 0; index < FactorNames.Length; index++)
                {
                    if (context.ActionArguments.TryGetValue(FactorNames[index], out var factorValue))
                    {
                        factorValues[index] = factorValue?.ToString();
                    }
                }
            }

            if (factorValues.All(string.IsNullOrEmpty))
            {
                _logger.LogWarning("Please config FactorNames.");

                await next();
                return;
            }
            //接口名字加参数对应的值做key值
            var idempotentKey = $"{context.HttpContext.Request.Path.Value}:{string.Join("-", factorValues)}";
           //查询key值在缓存是否存在
            var idempotentValue = await _cache.GetStringAsync(idempotentKey);
            if (idempotentValue != null)
            {
                //报错
                _logger.LogWarning("Received duplicate request({},{}), short-circuiting...", idempotentKey, idempotentValue);
                 throw Oops.Oh("系统繁忙请稍后尝试");
                //  context.Result = new AcceptedResult();
            }
            else
            {
                //设置缓存和 过去时间
                await _cache.SetStringAsync(idempotentKey, DateTimeOffset.UtcNow.ToString(),
                    new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = AbsoluteExpirationRelativeToNow });
                //继续执行
                await next();
            }
        }
    }

}
